﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;


using WebDavProcessor.Interfaces;
using WebDavProcessor.Resources;
using WebDavProcessor.Constants;
using WCFServer.Helpers;

namespace WCFServer.DataProviders
{
    abstract class DataAdapter:IWebDavIOProvider, IWebDavPropertyProvider
    {
        
        abstract public void WriteResource(ResourceInfo resource);
        abstract public void DeleteResource(ResourceInfo resource);
        abstract public void RenameResource(string oldResourceName, string newResourceName);
        abstract public bool IsExist(string resourcePath);
        abstract public ResourceInfo ReadResource(string resourcePath, int offset, int count);
        abstract public ResourceInfo ReadResourceLight(string resourcePath);

        public ResourceInfo ReadResource(string resourceName)
        {
            return ReadResource(resourceName, 0, -1);
        }


        #region IWebDavIOProvider
        public WebDavResource Read(string resourcePath)
        {
            try
            {
                string resourceName;
                string lockID;
                resourcePath.ParseResourceNameLock(out resourceName, out lockID);
                ResourceInfo res = ReadResource(resourceName);
                if (!res.Properties.ContainsKey("lockdiscovery") || string.IsNullOrEmpty(res.Properties["lockdiscovery"]) || res.Properties["lockdiscovery"] == lockID)
                {
                    WebDavStreamResource sres = new WebDavStreamResource(resourceName, res.Data);
                    return sres;
                }
                else
                {
                    WebDavResource resAccessError = new WebDavResource(resourcePath, WebDavStatusCodes.Locked);
                    return resAccessError;
                }
               
            }
            catch (Exception exc)
            {
                WebDavResource res = new WebDavResource(resourcePath, WebDavStatusCodes.InternalServerError);
                return res;
            }
            
        }
        public WebDavResource Read(string resourcePath, int offset, int count)
        {
            throw new NotImplementedException();
        }
        public WebDavResource Write(string resourcePath, System.IO.Stream data)
        {
            ResourceInfo info = new ResourceInfo(resourcePath);
            try
            {
                
                info.Data = data;
                WriteResource(info);
                return new WebDavResource(info.ResourceName);
            }
            catch (Exception)
            {
                WebDavResource res = new WebDavResource(info.ResourceName, WebDavStatusCodes.InternalServerError);
                return res;
            }
        }
        public WebDavResource Delete(string resourcePath)
        {
            ResourceInfo info = new ResourceInfo(resourcePath);
            try
            {
                DeleteResource(info);
                return new WebDavResource(info.ResourceName);
            }
            catch (Exception)
            {
                WebDavResource res = new WebDavResource(info.ResourceName, WebDavStatusCodes.InternalServerError);
                return res;
            }
        }
        public WebDavResource CreateCollection(string resourcePath)
        {
            throw new NotImplementedException();
        }
        public WebDavResource Copy(string resourcePath, string destinationPath)
        {
            throw new NotImplementedException();
        }
        public WebDavResource Move(string resourcePath, string destinationPath)
        {
            throw new NotImplementedException();
        }
        #endregion

        #region IWebDavPropertyProvider
        public WebDavResource GetAllProperties(string resourcePath, WebDavProcessor.Enumerations.WebDavDepth depth)
        {
            try
            {
                ResourceInfo info = ReadResourceLight(resourcePath);
                WebDavResourceProperties res = new WebDavResourceProperties(info.ResourceName);
                foreach (string key in info.Properties.Keys)
                    res.Properties.Add(new WebDavProperty(key, info.Properties[key]));
                return res;
            }
            catch (Exception exc)
            {
                WebDavResource res = new WebDavResource(resourcePath, WebDavStatusCodes.InternalServerError);
                return res;
            }
        }

        public WebDavResource GetAllProperties(string resourcePath, List<string> includedNames, WebDavProcessor.Enumerations.WebDavDepth depth)
        {
            throw new NotImplementedException();
        }

        public WebDavResource GetProperties(string resourcePath, List<string> propertyNames, WebDavProcessor.Enumerations.WebDavDepth depth)
        {
            try
            {
                ResourceInfo info = ReadResourceLight(resourcePath);
                WebDavResourceProperties res = new WebDavResourceProperties(info.ResourceName);
                foreach (string key in info.Properties.Keys)
                    if(propertyNames.Contains(key))
                        res.Properties.Add(new WebDavProperty(key, info.Properties[key]));
                return res;
            }
            catch (Exception exc)
            {
                WebDavResource res = new WebDavResource(resourcePath, WebDavStatusCodes.InternalServerError);
                return res;
            }
        }

        public WebDavResource GetPropertyNames(string resourcePath, WebDavProcessor.Enumerations.WebDavDepth depth)
        {
            return GetAllProperties(resourcePath, depth);
        }

        public WebDavResource UpdateProperties(string resourcePath, List<WebDavProperty> setProperties, List<string> removedProperties)
        {
            throw new NotImplementedException();
        }
        #endregion
    }

    class ResourceInfo
    {
        public string ResourceName { get; private set; }
        public Dictionary<string, string> Properties { get; set; }
        public System.IO.Stream Data { get; set;}

        public ResourceInfo()
        {
            Properties = new Dictionary<string, string>();
        }
        public ResourceInfo(string resourceName)
            :this()
        {
            ResourceName = resourceName;
        }
    }
}